package com.project.springboot.sseclient;

import com.gitee.yongzhuzl.commonutil.util.empty.EmptyUtil;
import com.project.springboot.exception.ResponseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 参考：<a href="https://blog.csdn.net/m0_74823963/article/details/145777371">...</a>
 * description: SSE工具类
 * @author 朱正磊
 * @date 2025-10-17 11:17:19
 */
@Slf4j
@Component
public class SseClient {

    private static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();

    /**
     * description: 创建sse连接
     * @author 朱正磊
     * @date 2025-10-17 14:10:19
     * @param uid 用户id
     * @return 返回sse发射器
     */
    public SseEmitter createSse(String uid) {
        // 默认30秒超时，设置为0L则永不超时
        SseEmitter sseEmitter = new SseEmitter(0L);
        // 完成后回调
        sseEmitter.onCompletion(() -> {
            log.info("用户[{}]结束连接......", uid);
            sseEmitterMap.remove(uid);
        });
        // 超时回调
        sseEmitter.onTimeout(() -> {
            log.error("用户[{}]连接超时......", uid);
        });
        // 异常回调
        sseEmitter.onError(throwable -> {
            try {
                log.error("用户[{}]连接异常，{}", uid, throwable.toString());
                sseEmitter.send(SseEmitter.event().id(uid).name("发生异常！")
                        .data("发生异常请重试！").reconnectTime(3000));
                sseEmitterMap.put(uid, sseEmitter);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        try {
            sseEmitter.send(SseEmitter.event().reconnectTime(5000));
            sseEmitterMap.put(uid, sseEmitter);
            log.info("用户[{}]创建sse连接成功！", uid);
            return sseEmitter;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 给用户发送消息
     * @author 朱正磊
     * @date 2025-10-17 14:10:09
     * @param uid 用户id
     * @param messageId 消息id
     * @param message 消息内容
     */
    public void sendMessage(String uid, String messageId, String message) {
        if (EmptyUtil.isEmpty(message)) {
            log.error("给用户[{}]发送消息失败，消息内容不能为空！", uid);
            throw new ResponseException("给用户" + uid + "发送消息失败，消息内容不能为空！");
        }
        SseEmitter sseEmitter = sseEmitterMap.get(uid);
        if (EmptyUtil.isEmpty(sseEmitter)) {
            log.error("给用户[{}]发送消息失败，还没有创建连接，请重试！", uid);
            throw new ResponseException("给用户" + uid + "发送消息失败，还没有创建连接，请重试！");
        }
        try {
            sseEmitter.send(SseEmitter.event().id(messageId).reconnectTime(60 * 1000L).data(message));
            log.info("给用户[{}]发送消息成功，消息id：{}，消息内容：{}", uid, messageId, message);
        } catch (IOException e) {
            sseEmitter.complete();
            sseEmitterMap.remove(uid);
            log.error("给用户[{}]发送消息失败，消息id：{}，消息内容：{}，错误信息：{}", uid, messageId, message, e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 断开sse连接
     * @author 朱正磊
     * @date 2025-10-17 14:49:59
     * @param uid 用户id
     */
    public void closeSse(String uid) {
        if (sseEmitterMap.containsKey(uid)) {
            SseEmitter sseEmitter = sseEmitterMap.get(uid);
            sseEmitter.complete();
            sseEmitterMap.remove(uid);
        } else {
            log.info("用户[{}]连接已关闭", uid);
        }
    }

}
